package withouther.system.plugins.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;
import withouther.system.core.base.BaseServiceImpl;
import withouther.system.core.util.page.PageQuery;
import withouther.system.core.util.page.PageUtils;

import withouther.system.plugins.system.entity.Menu;
import withouther.system.plugins.system.entity.Organization;
import withouther.system.plugins.system.entity.User;
import withouther.system.plugins.system.entity.dto.OrganizationDto;
import withouther.system.plugins.system.mapper.OrganizationMapper;
import withouther.system.plugins.system.service.OrganizationService;
import withouther.system.plugins.system.service.UserService;


@Service("organizationService")
@CacheConfig(cacheNames = "org")
public class OrganizationServiceImpl extends BaseServiceImpl<OrganizationMapper, Organization> implements OrganizationService {

    @Autowired
    private UserService userService;

    @Override
    @Cacheable
    public PageUtils queryPage(Map<String, Object> params) {
        String name = Convert.toStr(params.get("name"), "").trim();
        IPage<Organization> page = this.page(
                new PageQuery<Organization>().getPage(params),
                new QueryWrapper<Organization>().like(StrUtil.isNotEmpty(name), "name", name)
        );
        return new PageUtils(page);
    }

    @Override
//    @Cacheable
    public List<OrganizationDto> listOrg(Map<String, Object> params) {
        List<Organization> orgs = this.list(
                new QueryWrapper<Organization>().eq(StrUtil.isNotEmpty(Convert.toStr(params.get("name"))), "name", params.get("name"))
        );
        List<OrganizationDto> orgDtos = new ArrayList<>();
        for (Organization org : orgs) {
            OrganizationDto dto = new OrganizationDto();
            dto.setCreateTime(org.getCreateTime());
            dto.setId(org.getId());
            dto.setName(org.getName());
            dto.setParentId(org.getParentId());
            orgDtos.add(dto);
        }
        return orgDtos;
    }

    private List<OrganizationDto> treeChilOrg(List<Organization> orgs, List<OrganizationDto> orgDtos) {
        if (orgs.isEmpty()) {
            return orgDtos;
        }
        for (Organization org : orgs) {
            OrganizationDto dto = new OrganizationDto();
            dto.setCreateTime(org.getCreateTime());
            dto.setId(org.getId());
            dto.setName(org.getName());
            dto.setParentId(org.getParentId());
            treeChilOrg( selectParentOrg(org.getId()) , orgDtos);
            orgDtos.add(dto);
        }
        return orgDtos;
    }

    /**
     * 查询子机构
     * @param parentId
     * @return
     */
    private List<Organization> selectParentOrg(Long parentId) {
        return this.list( new QueryWrapper<Organization>().eq("parent_id", parentId));
    }

    @Override
//    @Cacheable
    public Object buildTree(Map<String, Object> params) {
        List<OrganizationDto> orgs = this.listOrg(params);
        Set<OrganizationDto> trees = new LinkedHashSet<>();
        Set<OrganizationDto> depts = new LinkedHashSet<>();
        List<String> deptNames = orgs.stream().map(OrganizationDto::getName).collect(Collectors.toList());
        boolean isChild;
        for (OrganizationDto org : orgs) {
            isChild = false;
            boolean isParent = "0".equals(org.getParentId().toString());
            if (isParent) {
                trees.add(org);
            }
            for (OrganizationDto it : orgs) {
                if (it.getParentId().equals(org.getId())) {
                    isChild = true;
                    if (org.getChildren() == null) {
                        org.setChildren(new ArrayList<>());
                    }
                    org.getChildren().add(it);
                }
            }
            if (isChild) {
                depts.add(org);
            } else if ((!isParent) && !deptNames.contains(this.baseMapper.selectById(org.getParentId()).getName())) {
                depts.add(org);
            }
        }
        if (trees == null || trees.isEmpty()) {
            trees = depts;
        }
        Integer totalElements = orgs.size();
        Map<String, Object> map = new HashMap<>(2);
        map.put("totalElements", totalElements);
        map.put("list", trees);
        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    public boolean removeByIds(List<Long> ids) {
        if (ids == null || ids.size() <= 0) {
            return false;
        }
        for (Long id : ids) {
            deleteTreeById(id);
        }
        return true;
    }

    private boolean deleteTreeById(Long id) {
        Map<String, Object> sqlMap = new HashMap<>();
        Organization org = this.baseMapper.selectById(id);
        sqlMap.put("parent_id", org.getId());
        List<Organization> orgs = this.baseMapper.selectByMap(sqlMap);
        if (orgs != null) {
            for (Organization organization : orgs) {
                deleteTreeById(organization.getId());
            }
        }
        this.baseMapper.deleteById(id);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    public boolean updateById(Organization org) {
        if (org.getId() == org.getParentId()) {
            throw new RuntimeException("上级不能为自己");
        }
        this.baseMapper.updateById(org);
        User user = new User();
        user.setOrgName(org.getName());
        //修改条件s
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq("org_id", org.getId());
        userService.update(user, userUpdateWrapper);
        return true;
    }
}